﻿/*  ------------------------------------------------------------------------
	 NQ Common Services Library
	 
	 Homepage: http://www.awzhome.de/
	 ------------------------------------------------------------------------
	 
	 The contents of this file are subject to the Mozilla Public License
	 Version 1.1 (the "License"); you may not use this file except in
	 compliance with the License. You may obtain a copy of the License at
	 http://www.mozilla.org/MPL/
	 
	 Software distributed under the License is distributed on an "AS IS"
	 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	 License for the specific language governing rights and limitations
	 under the License.
	
	 The Original Code is code of NQ Common Services Library.

	 The Initial Developer of the Original Code is Andreas Weizel.
	 Portions created by the Initial Developer are
	 Copyright (C) 2006-2011 Andreas Weizel. All Rights Reserved.
	 
	 Contributor(s): (none)
	 
	 Alternatively, the contents of this file may be used under the terms
	 of the GNU General Public License Version 2.0 or later (the "GPL"),
	 or the GNU Lesser General Public License Version 2.1 or later (the
	 "LGPL"), in which case the provisions of the GPL or the LGPL are
	 applicable instead of those above. If you wish to allow use of your
	 version of this file only under the terms of the GPL or the LGPL and
	 not to allow others to use your version of this file under the MPL,
	 indicate your decision by deleting the provisions above and replace
	 them with the notice and other provisions required by the GPL or the
	 LGPL. If you do not delete the provisions above, a recipient may use
	 your version of this file under the terms of any of the MPL, the GPL
	 or the LGPL.
	 ------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AWZhome.NQ.CommonServices.Visual;
using AWZhome.NQ.Core;
using AWZhome.NQ.Core.Fluent;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows;

namespace AWZhome.NQ.CommonServices
{
	[NQExportedService(Category = NQHostMode.GUI)]
	public class WizardDialogService : DependencyObject, Services.IWizardDialogService
	{
		private Dictionary<string, IView> _viewHashList = new Dictionary<string, IView>();
		private List<IView> _viewList = new List<IView>();
		private IView _activeView = null;
		private object _sharedData = null;
		private int _currentViewIndex = -1;
		private bool _goBackOnLastPage = true;
		private IContainer _parentContainer = null;
		private Size _maxClientSize;

		private WizardWindow _wizardWindow;

		#region Events

		public event EventHandler<NQCancelEventArgs> WizardClosing;
		public event EventHandler AdditionalButtonClicked;
		public event EventHandler WizardClosed;

		#endregion

		#region Dependency properties

		public static readonly DependencyProperty CancelEnabledProperty =
				DependencyProperty.Register("CancelEnabled", typeof(bool), typeof(WizardDialogService), new UIPropertyMetadata(true));

		public static readonly DependencyProperty GoForwardEnabledProperty =
				DependencyProperty.Register("GoForwardEnabled", typeof(bool), typeof(WizardDialogService), new UIPropertyMetadata(true));

		public static readonly DependencyProperty GoBackEnabledProperty =
				DependencyProperty.Register("GoBackEnabled", typeof(bool), typeof(WizardDialogService), new UIPropertyMetadata(true));

		public static readonly DependencyProperty AdditionalButtonTextProperty =
				DependencyProperty.Register("AdditionalButtonText", typeof(string), typeof(WizardDialogService), new UIPropertyMetadata(""));

		public static readonly DependencyProperty WizardCaptionProperty =
				DependencyProperty.Register("WizardCaption", typeof(string), typeof(WizardDialogService), new UIPropertyMetadata(String.Empty));

		public static readonly DependencyProperty WizardSubTitleProperty =
				DependencyProperty.Register("WizardSubTitle", typeof(string), typeof(WizardDialogService), new UIPropertyMetadata(String.Empty));

		public static readonly DependencyProperty WizardTitleProperty =
			DependencyProperty.Register("WizardTitle", typeof(string), typeof(WizardDialogService), new UIPropertyMetadata(String.Empty));

		#endregion

		#region Constructors, Destructors

		public WizardDialogService(IContainer parent)
		{
			_parentContainer = parent;

			_maxClientSize.Width = 0;
			_maxClientSize.Height = 0;

			// Initialize new wizard window
			_wizardWindow = new WizardWindow();
			_wizardWindow.DataContext = this;

			// Set event handlers
			_wizardWindow.Closed += new EventHandler(_wizardWindow_Closed);
			_wizardWindow.Closing += new System.ComponentModel.CancelEventHandler(_wizardWindow_Closing);
			_wizardWindow.buttonConf1.Click += new RoutedEventHandler(buttonConf1_Click);
			_wizardWindow.buttonPrev.Click += new RoutedEventHandler(buttonPrev_Click);
			_wizardWindow.buttonNext.Click += new RoutedEventHandler(buttonNext_Click);
		}

		~WizardDialogService()
		{
			_wizardWindow.Closed -= _wizardWindow_Closed;
			_wizardWindow.Closing -= _wizardWindow_Closing;
		}

		#endregion

		#region INQWizardDialogService Member

		public void AddView(IView newView, int position)
		{
			if (_viewHashList.ContainsKey(newView.Name) || (newView.DisplayMode != ViewDisplayMode.InClientArea))
			{
				return;
			}

			// Insert the view at the given position
			_viewHashList.Add(newView.Name, newView);
			_viewList.Insert(position, newView);
			newView.ViewManager = this;

			// Add visual view to window
			Control viewctl = newView.DisplayedObject as Control;
			if (viewctl != null)
			{
				// Set maximum view size
				if (viewctl.Height != Double.NaN)
				{
					if (viewctl.Height > _maxClientSize.Height)
					{
						_maxClientSize.Height = viewctl.Height;
						viewctl.Height = Double.NaN;
					}
				}
				if (viewctl.Width != Double.NaN)
				{
					if (viewctl.Width > _maxClientSize.Width)
					{
						_maxClientSize.Width = viewctl.Width;
						viewctl.Width = Double.NaN;
					}
				}

				// Reset the dialog size
				_wizardWindow.Height = _maxClientSize.Height + 140;
				_wizardWindow.Width = _maxClientSize.Width + 30;

				_wizardWindow.canvasClient.Children.Add(viewctl);
				viewctl.Visibility = System.Windows.Visibility.Hidden;
			}

			newView.LoadContents();

			// Restore current view
			if (_viewList.Count == 1)
			{
				this.ActiveView = newView;
			}
			else
			{
				IView curview = this.ActiveView;
				this.ActiveView = curview;
			}
		}

		public void GoNext()
		{
			// Activate next page
			if ((_currentViewIndex + 1) <= _viewList.Count)
			{
				_currentViewIndex++;
				this.ActiveView = _viewList[_currentViewIndex];
			}
		}

		public void GoBack()
		{
			// Activate previous page
			if (_currentViewIndex > 0)
			{
				_currentViewIndex--;
				this.ActiveView = _viewList[_currentViewIndex];
			}
		}

		public bool ShowWizard()
		{
			// Load settings
			this.LoadSettings();

			// Show the wizard window
			return _parentContainer.ShowModalDialog(_wizardWindow);
		}

		public void CloseWizard()
		{
			// Close the dialog
			if (_wizardWindow != null)
			{
				_wizardWindow.Close();
			}
		}

		public int IndexOfView(IView view)
		{
			return _viewList.IndexOf(view);
		}

		public int CurrentViewIndex
		{
			get
			{
				return _currentViewIndex;
			}
			set
			{
				this.ActiveView = _viewList[value];
			}
		}

		public object SharedData
		{
			get
			{
				return _sharedData;
			}
		}

		public string WizardTitle
		{
			get
			{
				return (string) GetValue(WizardTitleProperty);
			}
			set
			{
				SetValue(WizardTitleProperty, value);
			}
		}

		public string WizardSubTitle
		{
			get
			{
				return (string) GetValue(WizardSubTitleProperty);
			}
			set
			{
				SetValue(WizardSubTitleProperty, value);
			}
		}

		public string WizardCaption
		{
			get
			{
				return (string) GetValue(WizardCaptionProperty);
			}
			set
			{
				SetValue(WizardCaptionProperty, value);
			}
		}

		public bool GoBackOnLastPage
		{
			get
			{
				return _goBackOnLastPage;
			}
			set
			{
				_goBackOnLastPage = value;
			}
		}

		public bool ShowAdditionalButton
		{
			get
			{
				return (_wizardWindow.buttonConf1.Visibility == Visibility.Visible);
			}
			set
			{
				_wizardWindow.buttonConf1.Visibility = value ? Visibility.Visible : Visibility.Hidden;
			}
		}

		public string AdditionalButtonText
		{
			get
			{
				return (string) GetValue(AdditionalButtonTextProperty);
			}
			set
			{
				SetValue(AdditionalButtonTextProperty, value);
			}
		}

		public bool GoBackEnabled
		{
			get
			{
				return (bool) GetValue(GoBackEnabledProperty);
			}
			set
			{
				SetValue(GoBackEnabledProperty, value);
			}
		}

		public bool GoForwardEnabled
		{
			get
			{
				return (bool) GetValue(GoForwardEnabledProperty);
			}
			set
			{
				SetValue(GoForwardEnabledProperty, value);
			}
		}

		public bool CancelEnabled
		{
			get
			{
				return (bool) GetValue(CancelEnabledProperty);
			}
			set
			{
				SetValue(CancelEnabledProperty, value);
			}
		}

		#endregion

		#region INQViewManagerService Member

		public event System.EventHandler<ActiveViewChangedEventArgs> ActiveViewChanged;

		public void AddView(IView newView)
		{
			// Insert at the and of view list
			this.AddView(newView, _viewList.Count);
		}

		public void AddView(IView newView, bool activate)
		{
			// Parameter "activate" is not relevant in this context
			this.AddView(newView);
		}

		public void RemoveView(string viewName)
		{
			if (_viewHashList.ContainsKey(viewName))
			{
				// Save the view's settings
				_viewHashList[viewName].SaveContents(ViewSaveReason.ExplicitlyClosed);

				// Remove the visual view from container
				_wizardWindow.canvasClient.Children.Remove((Control) _viewHashList[viewName].DisplayedObject);

				// Remove the view instance from the internal lists
				_viewHashList[viewName].ViewManager = null;
				int oldIndex = _viewList.IndexOf(_viewHashList[viewName]);
				_viewList.Remove(_viewHashList[viewName]);
				_viewHashList.Remove(viewName);

				// Set the active view
				if (_viewList.Count > 0)
				{
					if (oldIndex >= 0)
					{
						if (oldIndex < _viewList.Count)
						{
							// We set the active view to the next view in the list
							this.ActiveView = _viewList[oldIndex];
						}
						else
						{
							// We make the last view active
							this.ActiveView = _viewList[_viewList.Count - 1];
						}
					}
				}
				else
				{
					// There aren't any views anymore
					this.ActiveView = null;
				}
			}
			else
			{
				RaiseViewNotFoundException(viewName);
			}
		}

		public void UpdateView(IView view, bool internalChange)
		{
			// It's not necessary to update the view in the wizard.
		}

		public void MoveView(IView view, IViewManager destManager)
		{
			throw new NotImplementedException("Moving of views is not possible in wizard managers.");
		}

		public int CountByDisplayMode(ViewDisplayMode displayMode)
		{
			return _viewList.Count;
		}

		public void LoadSettings()
		{
		}

		public void SaveSettings()
		{
			// Call SaveContents() on all views
			foreach (IView view in _viewList)
			{
				view.SaveContents(ViewSaveReason.ContainerClosed);
			}
		}

		public IView ActiveView
		{
			get
			{
				return _activeView;
			}
			set
			{
				if (value != _activeView)
				{
					if (value != null)
					{
						if (_viewHashList.ContainsValue(value))
						{
							//if ((_viewList.IndexOf(value) < (_currentViewIndex - 1)) || (_viewList.IndexOf(value) > (_currentViewIndex + 1)))
							//{
							//  // We may only activate the previous or next page
							//  RaiseInvalidWizardJumpException();
							//}
							//else
							//{
							if (value.DisplayMode == ViewDisplayMode.InClientArea)
							{
								// Activate the view
								if (_activeView != null)
								{
									((Control) _activeView.DisplayedObject).Visibility = System.Windows.Visibility.Hidden;
									_activeView.Deactivate(value);
								}
								value.Activate(_activeView);
								((Control) value.DisplayedObject).Visibility = System.Windows.Visibility.Visible;

								// Raise notification event
								IView oldview = _activeView;
								_activeView = value;
								_currentViewIndex = _viewList.IndexOf(_activeView);
								OnActiveViewChanged(oldview, value);
							}
							//}
						}
						else
						{
							// View not found
							RaiseViewNotFoundException(value.Name);
						}
					}
					else
					{
						// The new view is "null"
						_activeView.Deactivate(null);
						_activeView = null;
						_currentViewIndex = -1;
						OnActiveViewChanged(_activeView, null);
					}
				}

				// Update the wizard buttons
				if (_currentViewIndex == 0)
				{
					// This is the first page
					_wizardWindow.buttonPrev.Visibility = Visibility.Hidden;
				}
				else
				{
					_wizardWindow.buttonPrev.Visibility = Visibility.Visible;
				}
				if (_currentViewIndex >= _viewList.Count - 1)
				{
					// This is the last page
					_wizardWindow.buttonNext.Visibility = Visibility.Hidden;
					if (!_goBackOnLastPage)
					{
						_wizardWindow.buttonPrev.Visibility = Visibility.Hidden;
					}
					_wizardWindow.buttonClose.Visibility = Visibility.Visible;
					_wizardWindow.buttonCancel.Visibility = Visibility.Hidden;
				}
				else
				{
					// Any other case
					_wizardWindow.buttonNext.Visibility = Visibility.Visible;
					_wizardWindow.buttonClose.Visibility = Visibility.Hidden;
					_wizardWindow.buttonCancel.Visibility = Visibility.Visible;
				}
			}
		}

		public ISession ActiveSession
		{
			get
			{
				if (_activeView != null)
				{
					return _activeView.Session;
				}
				else
				{
					// Get default session
					ISessionManager sessionManager = ServiceCore
						.Get<Services.ISessionManagerService>()
						.To;
					return sessionManager.DefaultSession;
				}
			}
		}

		public IContainer Container
		{
			get
			{
				return _parentContainer;
			}
		}

		#endregion

		#region INQCollectionService<string,INQViewService> Member

		public IView this[string key]
		{
			get
			{
				return _viewHashList[key];
			}
		}

		public int Count
		{
			get
			{
				return _viewHashList.Count;
			}
		}

		#endregion

		#region IEnumerable<INQViewService> Member

		public IEnumerator<IView> GetEnumerator()
		{
			return ((IEnumerable<IView>) _viewHashList.Values).GetEnumerator();
		}

		#endregion

		#region IEnumerable Member

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return ((System.Collections.IEnumerable) _viewHashList.Values).GetEnumerator();
		}

		#endregion

		#region Private methods

		private void buttonPrev_Click(object sender, RoutedEventArgs e)
		{
			this.GoBack();
		}

		private void buttonNext_Click(object sender, RoutedEventArgs e)
		{
			this.GoNext();
		}

		private void buttonConf1_Click(object sender, RoutedEventArgs e)
		{
			if (this.AdditionalButtonClicked != null)
			{
				// Fire notification event for click on additional button
				this.AdditionalButtonClicked(this, new EventArgs());
			}
		}

		private void _wizardWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Fire request event and retrieve the cancel flag
			e.Cancel = this.OnWizardClosing();
		}

		private void _wizardWindow_Closed(object sender, EventArgs e)
		{
			// Save the setting when window is closed
			this.SaveSettings();

			// Fire corresponding event
			this.OnWizardClosed();
		}

		private void RaiseViewNotFoundException(string viewName)
		{
			throw new Exception("View " + viewName + " not found");
		}

		private void RaiseInvalidWizardJumpException()
		{
			throw new Exception("Invalid wizard jump.");
		}

		private void OnActiveViewChanged(IView oldview, IView newview)
		{
			if (this.ActiveViewChanged != null)
			{
				this.ActiveViewChanged(this, new ActiveViewChangedEventArgs(oldview, newview));
			}
		}

		private bool OnWizardClosing()
		{

			if (this.WizardClosing != null)
			{
				NQCancelEventArgs eventArgs = new NQCancelEventArgs();
				this.WizardClosing(this, eventArgs);
				return eventArgs.Cancel;
			}
			else
			{
				return false;
			}
		}

		private void OnWizardClosed()
		{
			if (this.WizardClosed != null)
			{
				this.WizardClosed(this, new EventArgs());
			}
		}

		#endregion
	}
}
